package cn.coder.jdbc2.executor;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import cn.coder.jdbc2.config.BoundSql;
import cn.coder.jdbc2.config.Configuration;
import cn.coder.jdbc2.config.MappedStatement;
import cn.coder.jdbc2.config.ParameterMapping;
import cn.coder.jdbc2.util.ClassUtil;

public class SimpleExecutor implements Executor {
	@Override
	public <T> List<T> selectList(Configuration configuration, MappedStatement mappedStatement, Object params)
			throws SQLException {
		// TODO Auto-generated method stub
		Connection connection = getConnection(configuration);

		return handleStatementSelect(connection, mappedStatement, params);
	}

	private Connection getConnection(Configuration configuration) throws SQLException {
		if (configuration == null || configuration.getDataSource() == null) {
			throw new RuntimeException("Configuration对象或者DataSource对象不能为null");
		}

		return configuration.getDataSource().getConnection();
	}

	private <E> List<E> handleStatementSelect(Connection connection, MappedStatement mappedStatement, Object params)
			throws SQLException {
		String statementType = mappedStatement.getStatementType();
		List<Object> result = null;
		// 不同statementType会有不同操作
		if ("prepared".equals(statementType)) {
			result = handlePreparedStatementSelect(connection, mappedStatement, params);
		} else {
			// other ....
		}

		return (List<E>) result;
	}

	/**
	 * JDBC操作
	 * 
	 * @param connection
	 * @param mappedStatement
	 * @param params
	 * @throws SQLException
	 */
	private <E> List<E> handlePreparedStatementSelect(Connection connection, MappedStatement mappedStatement,
			Object params) throws SQLException {
		// TODO Auto-generated method stub
		List<Object> result = new ArrayList<Object>();

		try {
			BoundSql boundSql = mappedStatement.getSqlSource().getBoundSql();
			String sql = boundSql.getOriginalSql();

			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			// 获得参数类型
			Class<?> parameterTypeClass = mappedStatement.getParameterTypeClass();
			// 获得参数名称
			List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

			if ("BASIC".equals(getParamenteTypeString(parameterTypeClass))) {
				preparedStatement.setObject(1, params);
			} else {
				// Object
				for (int i = 0; i < parameterMappings.size(); i++) {
					ParameterMapping parameterMapping = parameterMappings.get(i);
					String name = parameterMapping.getName();

					Object fieldValue = ClassUtil.getPrivateFieldValue(parameterTypeClass, name, params);
					preparedStatement.setObject(i + 1, fieldValue);
				}

				Class<?> resultTypeClass = mappedStatement.getResultTypeClass();
				ResultSet resultSet = preparedStatement.executeQuery();

				while (resultSet.next()) {
					// 遍历封装Result
					Object newInstance = resultTypeClass.newInstance();
					int columnCount = resultSet.getMetaData().getColumnCount();
					for (int i = 1; i <= columnCount; i++) {
						String columnName = resultSet.getMetaData().getColumnName(i);
						Field field = resultTypeClass.getDeclaredField(columnName);
						if (field != null) {
							if (!field.isAccessible())
								field.setAccessible(true);
							field.set(newInstance, resultSet.getObject(columnName));
						}
					}
					result.add(newInstance);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return (List<E>) result;
	}

	private String getParamenteTypeString(Class<?> parameterTypeClass) {
		// 八种基本类型以及String类型
		if (parameterTypeClass == Integer.class || parameterTypeClass == Double.class
				|| parameterTypeClass == String.class) {

			return "BASIC";
		} else {
			// .....Map和List以及Object的处理，这里先处理Object，有待扩展
			return "OBJECT";
		}
	}
}
